{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "\n",
    "from torch.utils.data import DataLoader\n",
    "from torch.utils.data import Dataset\n",
    "from torchvision import datasets\n",
    "\n",
    "from torchvision.transforms import ToTensor\n",
    "\n",
    "from torch.nn import functional as F\n",
    "from torch import nn , optim\n",
    "\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1-定义画图函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_curve(data):\n",
    "    plt.plot(range(len(data)),data,color='blue')\n",
    "    plt.legend(['velue'],loc=\"upper right\")\n",
    "    # plt.title(\"loss curve\")\n",
    "    plt.xlabel('step')\n",
    "    plt.ylabel('loss')\n",
    "    plt.show()\n",
    "\n",
    "def plot_image(img,label,name):\n",
    "    labels_map = {\n",
    "    0: \"T-Shirt\",\n",
    "    1: \"Trouser\",\n",
    "    2: \"Pullover\",\n",
    "    3: \"Dress\",\n",
    "    4: \"Coat\",\n",
    "    5: \"Sandal\",\n",
    "    6: \"Shirt\",\n",
    "    7: \"Sneaker\",\n",
    "    8: \"Bag\",\n",
    "    9: \"Ankle Boot\",\n",
    "    }\n",
    "    for i in range(6):\n",
    "        plt.subplot(2,3,i+1)\n",
    "        plt.tight_layout() # 自动调整间距\n",
    "        plt.imshow(img[i,0])\n",
    "        plt.title(\"{}:{}\".format(name,labels_map[label[i].item()]))\n",
    "        plt.xticks([])  #取消x，y坐标系\n",
    "        plt.yticks([])\n",
    "    plt.show()\n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2-加载数据集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def load_dataset():\n",
    "    training_data=datasets.FashionMNIST('../data',train=True,download=True,transform=ToTensor())    #加载一张训练图像的方式\n",
    "    train_loader = DataLoader(training_data,batch_size=64,shuffle=True)    #加载多张训练图像的方式\n",
    "\n",
    "    test_data = datasets.FashionMNIST('../data',train=False,download=True,transform=ToTensor())\n",
    "    test_loader = DataLoader(test_data,batch_size=64,shuffle=True)\n",
    "\n",
    "    return train_loader,test_loader\n",
    "                              "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 3 设计一个简单的MLP网络\n",
    "\n",
    "神经网络输入层应该为28*28，输出层是10\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Net(nn.Module):\n",
    "    def __init__(self):\n",
    "        super(Net,self).__init__()\n",
    "        self.fc1 = torch.nn.Linear(28*28,256)\n",
    "        self.fc2 = torch.nn.Linear(256,128)\n",
    "        self.fc3 = torch.nn.Linear(128,10)\n",
    "\n",
    "    def forward(self,x):\n",
    "        x = F.relu(self.fc1(x)) \n",
    "        x = F.relu(self.fc2(x))\n",
    "        x = self.fc3(x)\n",
    "        return x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def train(epoch_num,train_loader,net,optimizer,device):\n",
    "    train_loss=[]\n",
    "    for epoch in range(epoch_num):\n",
    "        for batch_idx,(x,y) in enumerate(train_loader):\n",
    "            x = x.to(device)\n",
    "            y = y.to(device)\n",
    "            x = x.view(x.size(0),28*28)\n",
    "            \n",
    "            #####################前向传播过程#######################\n",
    "            out = net(x)\n",
    "            # print(\"out:{},y:{}\".format(out.shape,y.shape))\n",
    "            y_onehot=F.one_hot(y,10).float()\n",
    "            loss = F.mse_loss(out,y_onehot)\n",
    "            optimizer.zero_grad()   #每一次计算梯度之前都要清零\n",
    "            ##############方向传播过程#################\n",
    "            loss.backward()\n",
    "            optimizer.step()\n",
    "            train_loss.append(loss.item())\n",
    "\n",
    "            if batch_idx % 100 == 0:\n",
    "                print(\"epoch:{},batch_idx:{},loss:{}\".format(epoch,batch_idx,loss.item()))\n",
    "    return train_loss\n",
    "\n",
    "          \n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "### 定义训练使用的设备#################\n",
    "device = (\n",
    "    \"cuda\" if torch.cuda.is_available()\n",
    "       \n",
    "    else \"cpu\"\n",
    ")\n",
    "######### 读取数据加载器#############################\n",
    "train_loader,test_loader = load_dataset()\n",
    "x,y = next(iter(train_loader))\n",
    "plot_image(x,y,'image sample')\n",
    "\n",
    "\n",
    "#############神经网络实例化,以及其他超参数##########################\n",
    "net = Net().to(device)\n",
    "print(\"device\",device)\n",
    "optimizer = optim.SGD(net.parameters(),lr=0.01)\n",
    "epoch_num = 1   #增加到5~10轮\n",
    "\n",
    "###################训练神经网络###########################\n",
    "train_loss = train(epoch_num,train_loader,net,optimizer,device)\n",
    "plot_curve(train_loss)\n",
    "\n",
    "#########################测试神经网络#################################\n",
    "total_correct = 0\n",
    "for x,y in test_loader:\n",
    "    x = x.to(device)\n",
    "    y = y.to(device)\n",
    "    x = x.view(x.size(0),28*28)\n",
    "    out = net(x)\n",
    "    pred = out.argmax(dim=1) #返回最大值索引\n",
    "    correct =pred.eq(y).sum().float().item()\n",
    "    total_correct += correct\n",
    "total_num = len(test_loader.dataset)\n",
    "acc = total_correct/total_num\n",
    "print(\"test acc:\",acc)\n",
    "\n",
    "############################可视化结果##############################\n",
    "x,y = next(iter(test_loader))\n",
    "x = x.to(device)\n",
    "y = y.to(device)\n",
    "\n",
    "out = net(x.view(x.size(0),28*28))\n",
    "pred = out.argmax(dim=1)\n",
    "###################取出数据到cpu########\n",
    "x = x.to(\"cpu\")\n",
    "pred = pred.to(\"cpu\")\n",
    "\n",
    "print(x.size(),pred.size())\n",
    "plot_image(x,pred,'predict sample')\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "dl2024",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.19"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
